home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / menus.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-02-18  |  64.2 KB  |  2,145 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <stdlib.h>
  22. #include <string.h>
  23.  
  24. #include <gtk/gtk.h>
  25. #include <gdk/gdkkeysyms.h>
  26.  
  27. #include "apptypes.h"
  28.  
  29. #include "appenv.h"
  30. #include "channels_dialog.h"
  31. #include "commands.h"
  32. #include "dialog_handler.h"
  33. #include "fileops.h"
  34. #include "gimprc.h"
  35. #include "gimpui.h"
  36. #include "interface.h"
  37. #include "layers_dialog.h"
  38. #include "menus.h"
  39. #include "paths_dialog.h"
  40. #include "paint_funcs.h"
  41. #include "preferences_dialog.h"
  42. #include "procedural_db.h"
  43. #include "scale.h"
  44. #include "tools.h"
  45. #include "gdisplay.h"
  46.  
  47. #include "libgimp/gimpenv.h"
  48.  
  49. #include "libgimp/gimpintl.h"
  50.  
  51.  
  52. #define MRU_MENU_ENTRY_SIZE (strlen ("/File/MRU00 ") + 1)
  53. #define MRU_MENU_ACCEL_SIZE sizeof ("<control>0")
  54.  
  55. static void   menus_create_item     (GtkItemFactory       *item_factory,
  56.                      GimpItemFactoryEntry *entry,
  57.                      gpointer              callback_data,
  58.                      guint                 callback_type);
  59. static void   menus_create_items    (GtkItemFactory       *item_factory,
  60.                      guint                 n_entries,
  61.                      GimpItemFactoryEntry *entries,
  62.                      gpointer              callback_data,
  63.                      guint                 callback_type);
  64. static void   menus_create_branches (GtkItemFactory      *item_factory,
  65.                      GimpItemFactoryEntry *entry);
  66. static void   menus_init            (void);
  67.  
  68. #ifdef ENABLE_NLS
  69. static gchar *menu_translate        (const gchar          *path,
  70.                      gpointer              data);
  71. #else
  72. #define menu_translate NULL
  73. #endif
  74.  
  75. static void   tearoff_cmd_callback  (GtkWidget            *widget,
  76.                      gpointer              callback_data,
  77.                      guint                 callback_action);
  78. static gint   tearoff_delete_cb     (GtkWidget          *widget, 
  79.                          GdkEvent          *event,
  80.                      gpointer           data);
  81. #ifdef ENABLE_DEBUG_ENTRY
  82. static void   menus_debug_recurse_menu (GtkWidget *menu,
  83.                     gint       depth,
  84.                     gchar     *path);
  85. static void   menus_debug_cmd_callback (GtkWidget *widget,
  86.                     gpointer   callback_data,
  87.                     guint      callback_action);
  88. #endif  /*  ENABLE_DEBUG_ENTRY  */
  89.  
  90. static GSList *last_opened_raw_filenames = NULL;
  91.  
  92. /*****  <Toolbox>  *****/
  93.  
  94. static GimpItemFactoryEntry toolbox_entries[] =
  95. {
  96.   /*  <Toolbox>/File  */
  97.  
  98.   /* the underscore installs an accelerator using the character that follows */
  99.   { { N_("/_File"), NULL, NULL, 0, "<Branch>" },
  100.     NULL, NULL },
  101.   { { N_("/File/New..."), "<control>N", file_new_cmd_callback, 0 },
  102.     "file/dialogs/file_new.html", NULL },
  103.   { { N_("/File/Open..."), "<control>O", file_open_cmd_callback, 0 },
  104.     "file/dialogs/file_open.html", NULL },
  105.  
  106.   /*  <Toolbox>/File/Acquire  */
  107.  
  108.   { { "/File/---", NULL, NULL, 0, "<Separator>" },
  109.     NULL, NULL },
  110.   { { N_("/File/Acquire"), NULL, NULL, 0, "<Branch>" },
  111.     NULL, NULL },
  112.  
  113.   { { "/File/---", NULL, NULL, 0, "<Separator>" },
  114.     NULL, NULL },
  115.   { { N_("/File/Preferences..."), NULL, prefs_cmd_callback, 0 },
  116.     "file/dialogs/preferences/preferences.html", NULL },
  117.  
  118.   /*  <Toolbox>/File/Dialogs  */
  119.  
  120.   { { "/File/---", NULL, NULL, 0, "<Separator>" },
  121.     NULL, NULL },
  122.   { { N_("/File/Dialogs/Layers, Channels & Paths..."), "<control>L", dialogs_lc_cmd_callback, 0 },
  123.     "file/dialogs/layers_and_channels.html", NULL },
  124.   { { N_("/File/Dialogs/Tool Options..."), "<control><shift>T", dialogs_tool_options_cmd_callback, 0 },
  125.     "file/dialogs/tool_options.html", NULL },
  126.  
  127.   { { "/File/Dialogs/---", NULL, NULL, 0, "<Separator>" },
  128.     NULL, NULL },
  129.   { { N_("/File/Dialogs/Brushes..."), "<control><shift>B", dialogs_brushes_cmd_callback, 0 },
  130.     "file/dialogs/brush_selection.html", NULL },
  131.   { { N_("/File/Dialogs/Patterns..."), "<control><shift>P", dialogs_patterns_cmd_callback, 0 },
  132.     "file/dialogs/pattern_selection.html", NULL },
  133.   { { N_("/File/Dialogs/Gradients..."), "<control>G", dialogs_gradients_cmd_callback, 0 },
  134.     "file/dialogs/gradient_selection.html", NULL },
  135.   { { N_("/File/Dialogs/Palette..."), "<control>P", dialogs_palette_cmd_callback, 0 },
  136.     "file/dialogs/palette_selection.html", NULL },
  137.   { { N_("/File/Dialogs/Indexed Palette..."), NULL, dialogs_indexed_palette_cmd_callback, 0 },
  138.     "file/dialogs/indexed_palette.html", NULL },
  139.  
  140.   { { "/File/Dialogs/---", NULL, NULL, 0, "<Separator>" },
  141.     NULL, NULL },
  142.   { { N_("/File/Dialogs/Input Devices..."), NULL, dialogs_input_devices_cmd_callback, 0 },
  143.     "file/dialogs/input_devices.html", NULL },
  144.   { { N_("/File/Dialogs/Device Status..."), NULL, dialogs_device_status_cmd_callback, 0 },
  145.     "file/dialogs/device_status.html", NULL },
  146.  
  147.   { { "/File/Dialogs/---", NULL, NULL, 0, "<Separator>" },
  148.     NULL, NULL },
  149.   { { N_("/File/Dialogs/Document Index..."), NULL, dialogs_document_index_cmd_callback, 0 },
  150.     "file/dialogs/document_index.html", NULL },
  151.   { { N_("/File/Dialogs/Error Console..."), NULL, dialogs_error_console_cmd_callback, 0 },
  152.     "file/dialogs/error_console.html", NULL },
  153. #ifdef DISPLAY_FILTERS
  154.   { { N_("/File/Dialogs/Display Filters..."), NULL, dialogs_display_filters_cmd_callback, 0 },
  155.     "file/dialogs/display_filters/display_filters.html", NULL },
  156. #endif /* DISPLAY_FILTERS */
  157.  
  158.   { { "/File/---", NULL, NULL, 0, "<Separator>" },
  159.     NULL, NULL },
  160.  
  161.   /*  MRU entries are inserted here  */
  162.  
  163.   { { "/File/---MRU", NULL, NULL, 0, "<Separator>" },
  164.     NULL, NULL },
  165.   { { N_("/File/Quit"), "<control>Q", file_quit_cmd_callback, 0 },
  166.     "file/quit.html", NULL },
  167.  
  168.   /*  <Toolbox>/Xtns  */
  169.  
  170.   /* the underscore installs an accelerator using the character that follows */
  171.   { { N_("/_Xtns"), NULL, NULL, 0, "<Branch>" },
  172.     NULL, NULL },
  173.   { { N_("/Xtns/Module Browser..."), NULL, dialogs_module_browser_cmd_callback, 0 },
  174.     "dialogs/module_browser.html", NULL },
  175.  
  176.   { { "/Xtns/---", NULL, NULL, 0, "<Separator>" },
  177.     NULL, NULL },
  178.  
  179.   /*  <Toolbox>/Help  */
  180.  
  181.   /* the underscore installs an accelerator using the character that follows */
  182.   { { N_("/_Help"), NULL, NULL, 0, "<Branch>" },
  183.     NULL, NULL },
  184.   { { N_("/Help/Help..."), "F1", help_help_cmd_callback, 0 },
  185.     "help/dialogs/help.html", NULL },
  186.   { { N_("/Help/Context Help..."), "<shift>F1", help_context_help_cmd_callback, 0 },
  187.     "help/context_help.html", NULL },
  188.   { { N_("/Help/Tip of the Day..."), NULL, help_tips_cmd_callback, 0 },
  189.     "help/dialogs/tip_of_the_day.html", NULL },
  190.   { { N_("/Help/About..."), NULL, help_about_cmd_callback, 0 },
  191.     "help/dialogs/about.html", NULL },
  192. #ifdef ENABLE_DEBUG_ENTRY
  193.   { { N_("/Help/Dump Items (Debug)"), NULL, menus_debug_cmd_callback, 0 },
  194.     NULL, NULL }
  195. #endif
  196. };
  197.  
  198. static guint n_toolbox_entries = (sizeof (toolbox_entries) /
  199.                   sizeof (toolbox_entries[0]));
  200. static GtkItemFactory *toolbox_factory = NULL;
  201.  
  202. /*****  <Image>  *****/
  203.  
  204. static GimpItemFactoryEntry image_entries[] =
  205. {
  206.   { { "/tearoff1", NULL, tearoff_cmd_callback, 0, "<Tearoff>" },
  207.     NULL, NULL },
  208.  
  209.   /*  <Image>/File  */
  210.  
  211.   { { N_("/File/New..."), "<control>N", file_new_cmd_callback, 1 },
  212.     "file/dialogs/file_new.html", NULL },
  213.   { { N_("/File/Open..."), "<control>O", file_open_cmd_callback, 0 },
  214.     "file/dialogs/file_open.html", NULL },
  215.   { { N_("/File/Save"), "<control>S", file_save_cmd_callback, 0 },
  216.     "file/dialogs/file_save.html", NULL },
  217.   { { N_("/File/Save As..."), NULL, file_save_as_cmd_callback, 0 },
  218.     "file/dialogs/file_save.html", NULL },
  219.   { { N_("/File/Revert..."), NULL, file_revert_cmd_callback, 0 },
  220.     "file/revert.html", NULL },
  221.  
  222.   { { "/File/---", NULL, NULL, 0, "<Separator>" },
  223.     NULL, NULL },
  224.   { { N_( "/File/Close"), "<control>W", file_close_cmd_callback, 0 },
  225.     "file/close.html", NULL },
  226.   { { N_("/File/Quit"), "<control>Q", file_quit_cmd_callback, 0 },
  227.     "file/quit.html", NULL },
  228.  
  229.   { { "/File/---moved", NULL, NULL, 0, "<Separator>" },
  230.     NULL, NULL },
  231.  
  232.   /*  <Image>/Edit  */
  233.  
  234.   { { N_("/Edit/Undo"), "<control>Z", edit_undo_cmd_callback, 0 },
  235.     "edit/undo.html", NULL },
  236.   { { N_("/Edit/Redo"), "<control>R", edit_redo_cmd_callback, 0 },
  237.     "edit/redo.html", NULL },
  238.  
  239.   { { "/Edit/---", NULL, NULL, 0, "<Separator>" },
  240.     NULL, NULL },
  241.   { { N_("/Edit/Cut"), "<control>X", edit_cut_cmd_callback, 0 },
  242.     "edit/cut.html", NULL },
  243.   { { N_("/Edit/Copy"), "<control>C", edit_copy_cmd_callback, 0 },
  244.     "edit/copy.html", NULL },
  245.   { { N_("/Edit/Paste"), "<control>V", edit_paste_cmd_callback, 0 },
  246.     "edit/paste.html", NULL },
  247.   { { N_("/Edit/Paste Into"), NULL, edit_paste_into_cmd_callback, 0 },
  248.     "edit/paste_into.html", NULL },
  249.   { { N_("/Edit/Paste as New"), NULL, edit_paste_as_new_cmd_callback, 0 },
  250.     "edit/paste_as_new.html", NULL },
  251.  
  252.   /*  <Image>/Edit/Buffer  */
  253.  
  254.   { { N_("/Edit/Buffer/Cut Named..."), "<control><shift>X", edit_named_cut_cmd_callback, 0 },
  255.     "edit/dialogs/cut_named.html", NULL },
  256.   { { N_("/Edit/Buffer/Copy Named..."), "<control><shift>C", edit_named_copy_cmd_callback, 0 },
  257.     "edit/dialogs/copy_named.html", NULL },
  258.   { { N_("/Edit/Buffer/Paste Named..."), "<control><shift>V", edit_named_paste_cmd_callback, 0 },
  259.     "edit/dialogs/paste_named.html", NULL },
  260.  
  261.   { { "/Edit/---", NULL, NULL, 0, "<Separator>" },
  262.     NULL, NULL },
  263.   { { N_("/Edit/Clear"), "<control>K", edit_clear_cmd_callback, 0 },
  264.     "edit/clear.html", NULL },
  265.   { { N_("/Edit/Fill with FG Color"), "<control>comma", edit_fill_cmd_callback, (guint)FOREGROUND_FILL },
  266.     "edit/fill.html", NULL },
  267.   { { N_("/Edit/Fill with BG Color"), "<control>period", edit_fill_cmd_callback, (guint)BACKGROUND_FILL },
  268.     "edit/fill.html", NULL },
  269.   { { N_("/Edit/Stroke"), NULL, edit_stroke_cmd_callback, 0 },
  270.     "edit/stroke.html", NULL },
  271.  
  272.   { { "/Edit/---", NULL, NULL, 0, "<Separator>" },
  273.     NULL, NULL },
  274.  
  275.   /*  <Image>/Select  */
  276.   
  277.   { { N_("/Select/Invert"), "<control>I", select_invert_cmd_callback, 0 },
  278.     "select/invert.html", NULL },
  279.   { { N_("/Select/All"), "<control>A", select_all_cmd_callback, 0 },
  280.     "select/all.html", NULL },
  281.   { { N_("/Select/None"), "<control><shift>A", select_none_cmd_callback, 0 },
  282.     "select/none.html", NULL },
  283.   { { N_("/Select/Float"), "<control><shift>L", select_float_cmd_callback, 0 },
  284.     "select/float.html", NULL },
  285.  
  286.   { { "/Select/---", NULL, NULL, 0, "<Separator>" },
  287.     NULL, NULL },
  288.   { { N_("/Select/Feather..."), "<control><shift>F", select_feather_cmd_callback, 0 },
  289.     "select/dialogs/feather_selection.html", NULL },
  290.   { { N_("/Select/Sharpen"), "<control><shift>H", select_sharpen_cmd_callback, 0 },
  291.     "select/sharpen.html", NULL },
  292.   { { N_("/Select/Shrink..."), NULL, select_shrink_cmd_callback, 0 },
  293.     "select/dialogs/shrink_selection.html", NULL },
  294.   { { N_("/Select/Grow..."), NULL, select_grow_cmd_callback, 0 },
  295.     "select/dialogs/grow_selection.html", NULL },
  296.   { { N_("/Select/Border..."), "<control><shift>B", select_border_cmd_callback, 0 },
  297.     "select/dialogs/border_selection.html", NULL },
  298.  
  299.   { { "/Select/---", NULL, NULL, 0, "<Separator>" },
  300.     NULL, NULL },
  301.   { { N_("/Select/Save to Channel"), NULL, select_save_cmd_callback, 0 },
  302.     "select/save_to_channel.html", NULL },
  303.  
  304.   /*  <Image>/View  */
  305.  
  306.   { { N_("/View/Zoom In"), "equal", view_zoomin_cmd_callback, 0 },
  307.     "view/zoom.html", NULL },
  308.   { { N_("/View/Zoom Out"), "minus", view_zoomout_cmd_callback, 0 },
  309.     "view/zoom.html", NULL },
  310.  
  311.   /*  <Image>/View/Zoom  */
  312.  
  313.   { { N_("/View/Zoom/16:1"), NULL, view_zoom_16_1_cmd_callback, 0 },
  314.     "view/zoom.html", NULL },
  315.   { { N_("/View/Zoom/8:1"), NULL, view_zoom_8_1_cmd_callback, 0 },
  316.     "view/zoom.html", NULL },
  317.   { { N_("/View/Zoom/4:1"), NULL, view_zoom_4_1_cmd_callback, 0 },
  318.     "view/zoom.html", NULL },
  319.   { { N_("/View/Zoom/2:1"), NULL, view_zoom_2_1_cmd_callback, 0 },
  320.     "view/zoom.html", NULL },
  321.   { { N_("/View/Zoom/1:1"), "1", view_zoom_1_1_cmd_callback, 0 },
  322.     "view/zoom.html", NULL },
  323.   { { N_("/View/Zoom/1:2"), NULL, view_zoom_1_2_cmd_callback, 0 },
  324.     "view/zoom.html", NULL },
  325.   { { N_("/View/Zoom/1:4"), NULL, view_zoom_1_4_cmd_callback, 0 },
  326.     "view/zoom.html", NULL },
  327.   { { N_("/View/Zoom/1:8"), NULL, view_zoom_1_8_cmd_callback, 0 },
  328.     "view/zoom.html", NULL },
  329.   { { N_("/View/Zoom/1:16"), NULL, view_zoom_1_16_cmd_callback, 0 },
  330.     "view/zoom.html", NULL },
  331.  
  332.   { { N_("/View/Dot for Dot"), NULL, view_dot_for_dot_cmd_callback, 0, "<ToggleItem>" },
  333.     "view/dot_for_dot.html", NULL },
  334.  
  335.   { { "/View/---", NULL, NULL, 0, "<Separator>" },
  336.     NULL, NULL },
  337.   { { N_("/View/Info Window..."), "<control><shift>I", view_info_window_cmd_callback, 0 },
  338.     "view/dialogs/info_window.html", NULL },
  339.   { { N_("/View/Nav. Window..."), "<control><shift>N", view_nav_window_cmd_callback, 0 },
  340.     "view/dialogs/navigation_window.html", NULL },
  341.  
  342.   { { "/View/---", NULL, NULL, 0, "<Separator>" },
  343.     NULL, NULL },
  344.   { { N_("/View/Toggle Selection"), "<control>T", view_toggle_selection_cmd_callback, 0, "<ToggleItem>" },
  345.     "view/toggle_selection.html", NULL },
  346.   { { N_("/View/Toggle Rulers"), "<control><shift>R", view_toggle_rulers_cmd_callback, 0, "<ToggleItem>" },
  347.     "view/toggle_rulers.html", NULL },
  348.   { { N_("/View/Toggle Statusbar"), "<control><shift>S", view_toggle_statusbar_cmd_callback, 0, "<ToggleItem>" },
  349.     "view/toggle_statusbar.html", NULL },
  350.   { { N_("/View/Toggle Guides"), "<control><shift>T", view_toggle_guides_cmd_callback, 0, "<ToggleItem>" },
  351.     "view/toggle_guides.html", NULL },
  352.   { { N_("/View/Snap to Guides"), NULL, view_snap_to_guides_cmd_callback, 0, "<ToggleItem>" },
  353.     "view/snap_to_guides.html", NULL },
  354.  
  355.   { { "/View/---", NULL, NULL, 0, "<Separator>" },
  356.     NULL, NULL },
  357.   { { N_("/View/New View"), NULL, view_new_view_cmd_callback, 0 },
  358.     "view/new_view.html", NULL },
  359.   { { N_("/View/Shrink Wrap"), "<control>E", view_shrink_wrap_cmd_callback, 0 },
  360.     "view/shrink_wrap.html", NULL },
  361.  
  362.   /*  <Image>/Image/Mode  */
  363.  
  364.   { { N_("/Image/Mode/RGB"), "<alt>R", image_convert_rgb_cmd_callback, 0 },
  365.     "image/mode/convert_to_rgb.html", NULL },
  366.   { { N_("/Image/Mode/Grayscale"), "<alt>G", image_convert_grayscale_cmd_callback, 0 },
  367.     "image/mode/convert_to_grayscale.html", NULL },
  368.   { { N_("/Image/Mode/Indexed..."), "<alt>I", image_convert_indexed_cmd_callback, 0 },
  369.     "image/mode/dialogs/convert_to_indexed.html", NULL },
  370.  
  371.   { { "/Image/Mode/---", NULL, NULL, 0, "<Separator>" },
  372.     NULL, NULL },
  373.  
  374.   /*  <Image>/Image/Colors  */
  375.  
  376.   { { N_("/Image/Colors/Desaturate"), NULL, image_desaturate_cmd_callback, 0 },
  377.     "image/colors/desaturate.html", NULL },
  378.   { { N_("/Image/Colors/Invert"), NULL, image_invert_cmd_callback, 0 },
  379.     "image/colors/invert.html", NULL },
  380.  
  381.   { { "/Image/Colors/---", NULL, NULL, 0, "<Separator>" },
  382.     NULL, NULL },
  383.  
  384.   /*  <Image>/Image/Colors/Auto  */
  385.  
  386.   { { N_("/Image/Colors/Auto/Equalize"), NULL, image_equalize_cmd_callback, 0 },
  387.     "image/colors/auto/equalize.html", NULL },
  388.  
  389.   { { "/Image/Colors/---", NULL, NULL, 0, "<Separator>" },
  390.     NULL, NULL },
  391.  
  392.   /*  <Image>/Image/Alpha  */
  393.  
  394.   { { N_("/Image/Alpha/Add Alpha Channel"), NULL, layers_add_alpha_channel_cmd_callback, 0 },
  395.     "layers/add_alpha_channel.html", NULL },
  396.  
  397.   /*  <Image>/Image/Transforms  */
  398.  
  399.   { { N_("/Image/Transforms/Offset..."), "<control><shift>O", image_offset_cmd_callback, 0 },
  400.     "image/transforms/dialogs/offset.html", NULL },
  401.   { { N_("/Image/Transforms/Rotate"), NULL, NULL, 0, "<Branch>" },
  402.     NULL, NULL },
  403.   { { "/Image/Transforms/---", NULL, NULL, 0, "<Separator>" },
  404.     NULL, NULL },
  405.  
  406.   { { "/Image/---", NULL, NULL, 0, "<Separator>" },
  407.     NULL, NULL },
  408.   { { N_("/Image/Canvas Size..."), NULL, image_resize_cmd_callback, 0 },
  409.     "image/dialogs/set_canvas_size.html", NULL },
  410.   { { N_("/Image/Scale Image..."), NULL, image_scale_cmd_callback, 0 },
  411.     "image/dialogs/scale_image.html", NULL },
  412.   { { N_("/Image/Duplicate"), "<control>D", image_duplicate_cmd_callback, 0 },
  413.     "image/duplicate.html", NULL },
  414.  
  415.   { { "/Image/---", NULL, NULL, 0, "<Separator>" },
  416.     NULL, NULL },
  417.  
  418.   /*  <Image>/Layers  */
  419.  
  420.   { { N_("/Layers/Layers, Channels & Paths..."), "<control>L", dialogs_lc_cmd_callback, 0 },
  421.     "dialogs/layers_and_channels.html", NULL },
  422.   { { "/Layers/---", NULL, NULL, 0, "<Separator>" },
  423.     NULL, NULL },
  424.   { { N_("/Layers/Layer to Imagesize"), NULL, layers_resize_to_image_cmd_callback, 0 },
  425.     "layers/layer_to_image_size.html", NULL },
  426.  
  427.   /*  <Image>/Layers/Stack  */
  428.  
  429.   { { N_("/Layers/Stack/Previous Layer"), "Prior", layers_previous_cmd_callback, 0 },
  430.     "layers/stack/stack.html#previous_layer", NULL },
  431.   { { N_("/Layers/Stack/Next Layer"), "Next", layers_next_cmd_callback, 0 },
  432.     "layers/stack/stack.html#next_layer", NULL },
  433.   { { N_("/Layers/Stack/Raise Layer"), "<shift>Prior", layers_raise_cmd_callback, 0 },
  434.     "layers/stack/stack.html#raise_layer", NULL },
  435.   { { N_("/Layers/Stack/Lower Layer"), "<shift>Next", layers_lower_cmd_callback, 0 },
  436.     "layers/stack/stack.html#lower_layer", NULL },
  437.   { { N_("/Layers/Stack/Layer to Top"), "<control>Prior", layers_raise_to_top_cmd_callback, 0 },
  438.     "layers/stack/stack.html#layer_to_top", NULL },
  439.   { { N_("/Layers/Stack/Layer to Bottom"), "<control>Next", layers_lower_to_bottom_cmd_callback, 0 },
  440.     "layers/stack/stack.html#layer_to_bottom", NULL },
  441.   { { "/Layers/Stack/---", NULL, NULL, 0, "<Separator>" },
  442.     NULL, NULL },
  443.  
  444.   /*  <Image>/Layers/Rotate  */
  445.  
  446.   { { N_("/Layers/Rotate"), NULL, NULL, 0, "<Branch>" },
  447.     NULL, NULL },
  448.  
  449.   { { "/Layers/---", NULL, NULL, 0, "<Separator>" },
  450.     NULL, NULL },
  451.   { { N_("/Layers/Anchor Layer"), "<control>H", layers_anchor_cmd_callback, 0 },
  452.     "layers/anchor_layer.html", NULL },
  453.   { { N_("/Layers/Merge Visible Layers..."), "<control>M", layers_merge_cmd_callback, 0 },
  454.     "layers/dialogs/merge_visible_layers.html", NULL },
  455.   { { N_("/Layers/Flatten Image"), NULL, layers_flatten_cmd_callback, 0 },
  456.     "layers/flatten_image.html", NULL },
  457.  
  458.   { { "/Layers/---", NULL, NULL, 0, "<Separator>" },
  459.     NULL, NULL },
  460.   { { N_("/Layers/Mask to Selection"), NULL, layers_mask_select_cmd_callback, 0 },
  461.     "layers/mask_to_selection.html", NULL },
  462.  
  463.   { { "/Layers/---", NULL, NULL, 0, "<Separator>" },
  464.     NULL, NULL },
  465.   { { N_("/Layers/Add Alpha Channel"), NULL, layers_add_alpha_channel_cmd_callback, 0 },
  466.     "layers/add_alpha_channel.html", NULL },
  467.   { { N_("/Layers/Alpha to Selection"), NULL, layers_alpha_select_cmd_callback, 0 },
  468.     "layers/alpha_to_selection.html", NULL },
  469.  
  470.   { { "/Layers/---", NULL, NULL, 0, "<Separator>" },
  471.     NULL, NULL },
  472.  
  473.   /*  <Image>/Tools  */
  474.  
  475.   { { N_("/Tools/Toolbox"), NULL, toolbox_raise_callback, 0 },
  476.     "toolbox/toolbox.html", NULL },
  477.   { { N_("/Tools/Default Colors"), "D", tools_default_colors_cmd_callback, 0 },
  478.     "toolbox/toolbox.html#default_colors", NULL },
  479.   { { N_("/Tools/Swap Colors"), "X", tools_swap_colors_cmd_callback, 0 },
  480.     "toolbox/toolbox.html#swap_colors", NULL },
  481.   { { "/Tools/---", NULL, NULL, 0, "<Separator>" },  
  482.     NULL, NULL },
  483.  
  484.   /*  <Image>/Dialogs  */
  485.  
  486.   { { N_("/Dialogs/Layers, Channels & Paths..."), "<control>L", dialogs_lc_cmd_callback, 0 },
  487.     "dialogs/layers_and_channels.html", NULL },
  488.   { { N_("/Dialogs/Tool Options..."), NULL, dialogs_tool_options_cmd_callback, 0 },
  489.     "dialogs/tool_options.html", NULL },
  490.  
  491.   { { "/Dialogs/---", NULL, NULL, 0, "<Separator>" },
  492.     NULL, NULL },
  493.   { { N_("/Dialogs/Brushes..."), "<control><shift>B", dialogs_brushes_cmd_callback, 0 },
  494.     "dialogs/brush_selection.html", NULL },
  495.   { { N_("/Dialogs/Patterns..."), "<control><shift>P", dialogs_patterns_cmd_callback, 0 },
  496.     "dialogs/pattern_selection.html", NULL },
  497.   { { N_("/Dialogs/Gradients..."), "<control>G", dialogs_gradients_cmd_callback, 0 },
  498.     "dialogs/gradient_selection.html", NULL },
  499.   { { N_("/Dialogs/Palette..."), "<control>P", dialogs_palette_cmd_callback, 0 },
  500.     "dialogs/palette_selection.html", NULL },
  501.   { { N_("/Dialogs/Indexed Palette..."), NULL, dialogs_indexed_palette_cmd_callback, 0 },
  502.     "dialogs/indexed_palette.html", NULL },
  503.  
  504.   { { "/Dialogs/---", NULL, NULL, 0, "<Separator>" },
  505.     NULL, NULL },
  506.   { { N_("/Dialogs/Input Devices..."), NULL, dialogs_input_devices_cmd_callback, 0 },
  507.     "dialogs/input_devices.html", NULL },
  508.   { { N_("/Dialogs/Device Status..."), NULL, dialogs_device_status_cmd_callback, 0 },
  509.     "dialogs/device_status.html", NULL },
  510.  
  511.   { { "/Dialogs/---", NULL, NULL, 0, "<Separator>" },
  512.     NULL, NULL },
  513.   { { N_("/Dialogs/Document Index..."), NULL, dialogs_document_index_cmd_callback, 0 },
  514.     "dialogs/document_index.html", NULL },
  515.   { { N_("/Dialogs/Error Console..."), NULL, dialogs_error_console_cmd_callback, 0 },
  516.     "dialogs/error_console.html", NULL },
  517. #ifdef DISPLAY_FILTERS
  518.   { { N_("/Dialogs/Display Filters..."), NULL, dialogs_display_filters_cmd_callback, 0 },
  519.     "dialogs/display_filters/display_filters.html", NULL },
  520. #endif /* DISPLAY_FILTERS */
  521.   { { N_("/Dialogs/Undo History..."), NULL, dialogs_undo_history_cmd_callback, 0},
  522.     "dialogs/undo_history.html", NULL },
  523.  
  524.  
  525.   { { "/---", NULL, NULL, 0, "<Separator>" },
  526.     NULL, NULL },
  527.  
  528.   /*  <Image>/Filters  */
  529.  
  530.   { { N_("/Filters/Repeat Last"), "<alt>F", filters_repeat_cmd_callback, 0x0 },
  531.     "filters/repeat_last.html", NULL },
  532.   { { N_("/Filters/Re-Show Last"), "<alt><shift>F", filters_repeat_cmd_callback, 0x1 },
  533.     "filters/reshow_last.html", NULL },
  534.  
  535.   { { "/Filters/---", NULL, NULL, 0, "<Separator>" },
  536.     NULL, NULL },
  537.   { { N_("/Filters/Blur"), NULL, NULL, 0, "<Branch>" },
  538.     NULL, NULL },
  539.   { { N_("/Filters/Colors"), NULL, NULL, 0, "<Branch>" },
  540.     NULL, NULL },
  541.   { { N_("/Filters/Noise"), NULL, NULL, 0, "<Branch>" },
  542.     NULL, NULL },
  543.   { { N_("/Filters/Edge-Detect"), NULL, NULL, 0, "<Branch>" },
  544.     NULL, NULL },
  545.   { { N_("/Filters/Enhance"), NULL, NULL, 0, "<Branch>" },
  546.     NULL, NULL },
  547.   { { N_("/Filters/Generic"), NULL, NULL, 0, "<Branch>" },
  548.     NULL, NULL },
  549.  
  550.   { { "/Filters/---", NULL, NULL, 0, "<Separator>" },
  551.     NULL, NULL },
  552.   { { N_("/Filters/Glass Effects"), NULL, NULL, 0, "<Branch>" },
  553.     NULL, NULL },
  554.   { { N_("/Filters/Light Effects"), NULL, NULL, 0, "<Branch>" },
  555.     NULL, NULL },
  556.   { { N_("/Filters/Distorts"), NULL, NULL, 0, "<Branch>" },
  557.     NULL, NULL },
  558.   { { N_("/Filters/Artistic"), NULL, NULL, 0, "<Branch>" },
  559.     NULL, NULL },
  560.   { { N_("/Filters/Map"), NULL, NULL, 0, "<Branch>" },
  561.     NULL, NULL },
  562.   { { N_("/Filters/Render"), NULL, NULL, 0, "<Branch>" },
  563.     NULL, NULL },
  564.   { { N_("/Filters/Web"), NULL, NULL, 0, "<Branch>" },
  565.     NULL, NULL },
  566.  
  567.   { { "/Filters/---INSERT", NULL, NULL, 0, "<Separator>" },
  568.     NULL, NULL },
  569.   { { N_("/Filters/Animation"), NULL, NULL, 0, "<Branch>" },
  570.     NULL, NULL },
  571.   { { N_("/Filters/Combine"), NULL, NULL, 0, "<Branch>" },
  572.     NULL, NULL },
  573.  
  574.   { { "/Filters/---", NULL, NULL, 0, "<Separator>" },
  575.     NULL, NULL },
  576.   { { N_("/Filters/Toys"), NULL, NULL, 0, "<Branch>" },
  577.     NULL, NULL },
  578. };
  579. static guint n_image_entries = (sizeof (image_entries) /
  580.                 sizeof (image_entries[0]));
  581. static GtkItemFactory *image_factory = NULL;
  582.  
  583. /*****  <Load>  *****/
  584.  
  585. static GimpItemFactoryEntry load_entries[] =
  586. {
  587.   { { N_("/Automatic"), NULL, file_open_by_extension_callback, 0 },
  588.     "open_by_extension.html", NULL },
  589.  
  590.   { { "/---", NULL, NULL, 0, "<Separator>" },
  591.     NULL, NULL }
  592. };
  593. static guint n_load_entries = (sizeof (load_entries) /
  594.                    sizeof (load_entries[0]));
  595. static GtkItemFactory *load_factory = NULL;
  596.   
  597. /*****  <Save>  *****/
  598.  
  599. static GimpItemFactoryEntry save_entries[] =
  600. {
  601.   { { N_("/By Extension"), NULL, file_save_by_extension_callback, 0 },
  602.     "save_by_extension.html", NULL },
  603.  
  604.   { { "/---", NULL, NULL, 0, "<Separator>" },
  605.     NULL, NULL },
  606. };
  607. static guint n_save_entries = (sizeof (save_entries) /
  608.                    sizeof (save_entries[0]));
  609. static GtkItemFactory *save_factory = NULL;
  610.  
  611. /*****  <Layers>  *****/
  612.  
  613. static GimpItemFactoryEntry layers_entries[] =
  614. {
  615.   { { N_("/New Layer..."), "<control>N", layers_dialog_new_layer_callback, 0 },
  616.     "dialogs/new_layer.html", NULL },
  617.  
  618.   /*  <Layers>/Stack  */
  619.  
  620.   { { N_("/Stack/Raise Layer"), "<control>F", layers_dialog_raise_layer_callback, 0 },
  621.     "stack/stack.html#raise_layer", NULL },
  622.   { { N_("/Stack/Lower Layer"), "<control>B", layers_dialog_lower_layer_callback, 0 },
  623.     "stack/stack.html#lower_layer", NULL },
  624.   { { N_("/Stack/Layer to Top"), "<shift><control>F", layers_dialog_raise_layer_to_top_callback, 0 },
  625.     "stack/stack.html#later_to_top", NULL },
  626.   { { N_("/Stack/Layer to Bottom"), "<shift><control>B", layers_dialog_lower_layer_to_bottom_callback, 0 },
  627.     "stack/stack.html#layer_to_bottom", NULL },
  628.  
  629.   { { N_("/Duplicate Layer"), "<control>C", layers_dialog_duplicate_layer_callback, 0 },
  630.     "duplicate_layer.html", NULL },
  631.   { { N_("/Anchor Layer"), "<control>H", layers_dialog_anchor_layer_callback, 0 },
  632.     "anchor_layer.html", NULL },
  633.   { { N_("/Delete Layer"), "<control>X", layers_dialog_delete_layer_callback, 0 },
  634.     "delete_layer.html", NULL },
  635.  
  636.   { { "/---", NULL, NULL, 0, "<Separator>" },
  637.     NULL, NULL },
  638.   { { N_("/Layer Boundary Size..."), "<control>R", layers_dialog_resize_layer_callback, 0 },
  639.     "dialogs/layer_boundary_size.html", NULL },
  640.   { { N_("/Layer to Imagesize"), NULL, layers_dialog_resize_to_image_callback, 0 },
  641.     "layer_to_image_size.html", NULL },
  642.   { { N_("/Scale Layer..."), "<control>S", layers_dialog_scale_layer_callback, 0 },
  643.     "dialogs/scale_layer.html", NULL },
  644.       
  645.   { { "/---", NULL, NULL, 0, "<Separator>" },
  646.     NULL, NULL },
  647.   { { N_("/Merge Visible Layers..."), "<control>M", layers_dialog_merge_layers_callback, 0 },
  648.     "dialogs/merge_visible_layers.html", NULL },
  649.   { { N_("/Merge Down"), "<control><shift>M", layers_dialog_merge_down_callback, 0 },
  650.     "merge_down.html", NULL },
  651.   { { N_("/Flatten Image"), NULL, layers_dialog_flatten_image_callback, 0 },
  652.     "flatten_image.html", NULL },
  653.  
  654.   { { "/---", NULL, NULL, 0, "<Separator>" },
  655.     NULL, NULL },
  656.   { { N_("/Add Layer Mask..."), NULL, layers_dialog_add_layer_mask_callback, 0 },
  657.     "dialogs/add_layer_mask.html", NULL },
  658.   { { N_("/Apply Layer Mask"), NULL, layers_dialog_apply_layer_mask_callback, 0 },
  659.     "apply_mask.html", NULL },
  660.   { { N_("/Delete Layer Mask"), NULL, layers_dialog_delete_layer_mask_callback, 0 },
  661.     "delete_mask.html", NULL },
  662.   { { N_("/Mask to Selection"), NULL, layers_dialog_mask_select_callback, 0 },
  663.     "mask_to_selection.html", NULL },
  664.  
  665.   { { "/---", NULL, NULL, 0, "<Separator>" },
  666.     NULL, NULL },
  667.   { { N_("/Add Alpha Channel"), NULL, layers_dialog_add_alpha_channel_callback, 0 },
  668.     "add_alpha_channel.html", NULL },
  669.   { { N_("/Alpha to Selection"), NULL, layers_dialog_alpha_select_callback, 0 },
  670.     "alpha_to_selection.html", NULL },
  671.  
  672.   { { "/---", NULL, NULL, 0, "<Separator>" },
  673.     NULL, NULL },
  674.   { { N_("/Edit Layer Attributes..."), NULL, layers_dialog_edit_layer_attributes_callback, 0 },
  675.     "dialogs/edit_layer_attributes.html", NULL }
  676. };
  677. static guint n_layers_entries = (sizeof (layers_entries) /
  678.                  sizeof (layers_entries[0]));
  679. static GtkItemFactory *layers_factory = NULL;
  680.  
  681. /*****  <Channels>  *****/
  682.  
  683. static GimpItemFactoryEntry channels_entries[] =
  684. {
  685.   { { N_("/New Channel..."), "<control>N", channels_dialog_new_channel_callback, 0 },
  686.     "dialogs/new_channel.html", NULL },
  687.   { { N_("/Raise Channel"), "<control>F", channels_dialog_raise_channel_callback, 0 },
  688.     "raise_channel.html", NULL },
  689.   { { N_("/Lower Channel"), "<control>B", channels_dialog_lower_channel_callback, 0 },
  690.     "lower_channel.html", NULL },
  691.   { { N_("/Duplicate Channel"), "<control>C", channels_dialog_duplicate_channel_callback, 0 },
  692.     "duplicate_channel.html", NULL },
  693.  
  694.   { { "/---", NULL, NULL, 0, "<Separator>" },
  695.     NULL, NULL },
  696.   { { N_("/Channel to Selection"), "<control>S", channels_dialog_channel_to_sel_callback, 0 },
  697.     "channel_to_selection.html", NULL },
  698.   { { N_("/Add to Selection"), NULL, channels_dialog_add_channel_to_sel_callback, 0 },
  699.     "channel_to_selection.html#add", NULL },
  700.   { { N_("/Subtract from Selection"), NULL, channels_dialog_sub_channel_from_sel_callback, 0 },
  701.     "channel_to_selection.html#subtract", NULL },
  702.   { { N_("/Intersect with Selection"), NULL, channels_dialog_intersect_channel_with_sel_callback, 0 },
  703.     "channel_to_selection.html#intersect", NULL },
  704.  
  705.   { { "/---", NULL, NULL, 0, "<Separator>" },
  706.     NULL, NULL },
  707.   { { N_("/Delete Channel"), "<control>X", channels_dialog_delete_channel_callback, 0 },
  708.     "delete_channel.html", NULL },
  709.  
  710.   { { "/---", NULL, NULL, 0, "<Separator>" },
  711.     NULL, NULL },
  712.   { { N_("/Edit Channel Attributes..."), NULL, channels_dialog_edit_channel_attributes_callback, 0 },
  713.     "dialogs/edit_channel_attributes.html", NULL }
  714. };
  715. static guint n_channels_entries = (sizeof (channels_entries) /
  716.                    sizeof (channels_entries[0]));
  717. static GtkItemFactory *channels_factory = NULL;
  718.  
  719. /*****  <Paths>  *****/
  720.  
  721. static GimpItemFactoryEntry paths_entries[] =
  722. {
  723.   { { N_("/New Path"), "<control>N", paths_dialog_new_path_callback, 0 },
  724.     "new_path.html", NULL },
  725.   { { N_("/Duplicate Path"), "<control>U", paths_dialog_dup_path_callback, 0 },
  726.     "duplicate_path.html", NULL },
  727.   { { N_("/Path to Selection"), "<control>S", paths_dialog_path_to_sel_callback, 0 },
  728.     "path_to_selection.html", NULL },
  729.   { { N_("/Selection to Path"), "<control>P", paths_dialog_sel_to_path_callback, 0 },
  730.     "filters/sel2path.html", NULL },
  731.   { { N_("/Stroke Path"), "<control>T", paths_dialog_stroke_path_callback, 0 },
  732.     "stroke_path.html", NULL },
  733.   { { N_("/Delete Path"), "<control>X", paths_dialog_delete_path_callback, 0 },
  734.     "delete_path.html", NULL },
  735.  
  736.   { { "/---", NULL, NULL, 0, "<Separator>" },
  737.     NULL, NULL },
  738.   { { N_("/Copy Path"), "<control>C", paths_dialog_copy_path_callback, 0 },
  739.     "copy_path.html", NULL },
  740.   { { N_("/Paste Path"), "<control>V", paths_dialog_paste_path_callback, 0 },
  741.     "paste_path.html", NULL },
  742.   { { N_("/Import Path..."), "<control>I", paths_dialog_import_path_callback, 0 },
  743.     "dialogs/import_path.html", NULL },
  744.   { { N_("/Export Path..."), "<control>E", paths_dialog_export_path_callback, 0 },
  745.     "dialogs/export_path.html", NULL },
  746.  
  747.   { { "/---", NULL, NULL, 0, "<Separator>" },
  748.     NULL, NULL },
  749.   { { N_("/Edit Path Attributes..."), NULL, paths_dialog_edit_path_attributes_callback, 0 },
  750.     "dialogs/edit_path_attributes.html", NULL }
  751. };
  752. static guint n_paths_entries = (sizeof (paths_entries) /
  753.                 sizeof (paths_entries[0]));
  754. static GtkItemFactory *paths_factory = NULL;
  755.  
  756. static gboolean menus_initialized = FALSE;
  757.  
  758. void
  759. menus_get_toolbox_menubar (GtkWidget     **menubar,
  760.                GtkAccelGroup **accel_group)
  761. {
  762.   if (!menus_initialized)
  763.     menus_init ();
  764.   
  765.   if (menubar)
  766.     *menubar = toolbox_factory->widget;
  767.   if (accel_group)
  768.     *accel_group = toolbox_factory->accel_group;
  769. }
  770.  
  771. void
  772. menus_get_image_menu (GtkWidget     **menu,
  773.               GtkAccelGroup **accel_group)
  774. {
  775.   if (!menus_initialized)
  776.     menus_init ();
  777.  
  778.   if (menu)
  779.     *menu = image_factory->widget;
  780.   if (accel_group)
  781.     *accel_group = image_factory->accel_group;
  782. }
  783.  
  784. void
  785. menus_get_load_menu (GtkWidget     **menu,
  786.              GtkAccelGroup **accel_group)
  787. {
  788.   if (!menus_initialized)
  789.     menus_init ();
  790.  
  791.   if (menu)
  792.     *menu = load_factory->widget;
  793.   if (accel_group)
  794.     *accel_group = load_factory->accel_group;
  795. }
  796.  
  797. void
  798. menus_get_save_menu (GtkWidget     **menu,
  799.              GtkAccelGroup **accel_group)
  800. {
  801.   if (!menus_initialized)
  802.     menus_init ();
  803.  
  804.   if (menu)
  805.     *menu = save_factory->widget;
  806.   if (accel_group)
  807.     *accel_group = save_factory->accel_group;
  808. }
  809.  
  810. void
  811. menus_get_layers_menu (GtkWidget     **menu,
  812.                GtkAccelGroup **accel_group)
  813. {
  814.   if (!menus_initialized)
  815.     menus_init ();
  816.  
  817.   if (menu)
  818.     *menu = layers_factory->widget;
  819.   if (accel_group)
  820.     *accel_group = layers_factory->accel_group;
  821. }
  822.  
  823. void
  824. menus_get_channels_menu (GtkWidget     **menu,
  825.              GtkAccelGroup **accel_group)
  826. {
  827.   if (!menus_initialized)
  828.     menus_init ();
  829.  
  830.   if (menu)
  831.     *menu = channels_factory->widget;
  832.   if (accel_group)
  833.     *accel_group = channels_factory->accel_group;
  834. }
  835.  
  836. void
  837. menus_get_paths_menu (GtkWidget     **menu,
  838.               GtkAccelGroup **accel_group)
  839. {
  840.   if (!menus_initialized)
  841.     menus_init ();
  842.  
  843.   if (menu)
  844.     *menu = paths_factory->widget;
  845.   if (accel_group)
  846.     *accel_group = paths_factory->accel_group;
  847. }
  848.  
  849. void
  850. menus_create_item_from_full_path (GimpItemFactoryEntry *entry,
  851.                   gchar                *domain_name,
  852.                   gpointer              callback_data)
  853. {
  854.   GtkItemFactory *item_factory;
  855.   gchar          *path;
  856.  
  857.   g_return_if_fail (entry != NULL);
  858.  
  859.   if (!menus_initialized)
  860.     menus_init ();
  861.  
  862.   path = entry->entry.path;
  863.  
  864.   if (!path)
  865.     return;
  866.  
  867.   item_factory = gtk_item_factory_from_path (path);
  868.  
  869.   if (!item_factory)
  870.     {
  871.       g_warning ("entry refers to unknown item factory: \"%s\"", path);
  872.       return;
  873.     }
  874.  
  875.   gtk_object_set_data (GTK_OBJECT (item_factory), "textdomain", domain_name);
  876.  
  877.   while (*path != '>')
  878.     path++;
  879.   path++;
  880.  
  881.   entry->entry.path = path;
  882.  
  883.   menus_create_item (item_factory, entry, callback_data, 2);
  884. }
  885.  
  886. static void
  887. menus_create_branches (GtkItemFactory       *item_factory,
  888.                GimpItemFactoryEntry *entry)
  889. {
  890.   GString *tearoff_path;
  891.   gint     factory_length;
  892.   gchar   *p;
  893.   gchar   *path;
  894.  
  895.   if (! entry->entry.path)
  896.     return;
  897.  
  898.   tearoff_path = g_string_new ("");
  899.  
  900.   path = entry->entry.path;
  901.   p = strchr (path, '/');
  902.   factory_length = p - path;
  903.  
  904.   /*  skip the first slash  */
  905.   if (p)
  906.     p = strchr (p + 1, '/');
  907.  
  908.   while (p)
  909.     {
  910.       g_string_assign (tearoff_path, path + factory_length);
  911.       g_string_truncate (tearoff_path, p - path - factory_length);
  912.  
  913.       if (!gtk_item_factory_get_widget (item_factory, tearoff_path->str))
  914.     {
  915.       GimpItemFactoryEntry branch_entry =
  916.       {
  917.         { NULL, NULL, NULL, 0, "<Branch>" },
  918.         NULL,
  919.         NULL
  920.       };
  921.  
  922.       branch_entry.entry.path = tearoff_path->str;
  923.       gtk_object_set_data (GTK_OBJECT (item_factory), "complete", path);
  924.       menus_create_item (item_factory, &branch_entry, NULL, 2);
  925.       gtk_object_remove_data (GTK_OBJECT (item_factory), "complete");
  926.     }
  927.  
  928.       g_string_append (tearoff_path, "/tearoff1");
  929.  
  930.       if (!gtk_item_factory_get_widget (item_factory, tearoff_path->str))
  931.     {
  932.       GimpItemFactoryEntry tearoff_entry =
  933.       {
  934.         { NULL, NULL, tearoff_cmd_callback, 0, "<Tearoff>" },
  935.         NULL,
  936.         NULL
  937.       };
  938.  
  939.       tearoff_entry.entry.path = tearoff_path->str;
  940.       menus_create_item (item_factory, &tearoff_entry, NULL, 2);
  941.     }
  942.  
  943.       p = strchr (p + 1, '/');
  944.     }
  945.  
  946.   g_string_free (tearoff_path, TRUE);
  947. }
  948.  
  949. static void
  950. menus_filters_subdirs_to_top (GtkMenu *menu)
  951. {
  952.   GtkMenuItem *menu_item;
  953.   GList *list;
  954.   gboolean submenus_passed = FALSE;
  955.   gint pos;
  956.   gint items;
  957.  
  958.   pos = 1;
  959.   items = 0;
  960.  
  961.   for (list = GTK_MENU_SHELL (menu)->children; list; list = g_list_next (list))
  962.     {
  963.       menu_item = GTK_MENU_ITEM (list->data);
  964.       items++;
  965.       
  966.       if (menu_item->submenu)
  967.     {
  968.       if (submenus_passed)
  969.         {
  970.           menus_filters_subdirs_to_top (GTK_MENU (menu_item->submenu));
  971.           gtk_menu_reorder_child (menu, GTK_WIDGET (menu_item), pos++);
  972.         }
  973.     }
  974.       else
  975.     {
  976.       submenus_passed = TRUE;
  977.     }
  978.     }
  979.  
  980.   if (pos > 1 && items > pos)
  981.     {
  982.       GtkWidget *separator;
  983.  
  984.       separator = gtk_menu_item_new ();
  985.       gtk_menu_insert (menu, separator, pos);
  986.       gtk_widget_show (separator);
  987.     }
  988. }
  989.  
  990. void
  991. menus_reorder_plugins (void)
  992. {
  993.   static gchar *rotate_plugins[] = { "90 degrees",
  994.                      "180 degrees",
  995.                                      "270 degrees" };
  996.   static gint n_rotate_plugins = (sizeof (rotate_plugins) /
  997.                   sizeof (rotate_plugins[0]));
  998.  
  999.   static gchar *image_file_entries[] = { "---moved",
  1000.                      "Close",
  1001.                      "Quit" };
  1002.   static gint n_image_file_entries = (sizeof (image_file_entries) /
  1003.                       sizeof (image_file_entries[0]));
  1004.  
  1005.   static gchar *reorder_submenus[] = { "<Image>/Video",
  1006.                        "<Image>/Script-Fu" };
  1007.   static gint n_reorder_submenus = (sizeof (reorder_submenus) /
  1008.                     sizeof (reorder_submenus[0]));
  1009.  
  1010.   static gchar *reorder_subsubmenus[] = { "<Image>/Filters",
  1011.                       "<Toolbox>/Xtns" };
  1012.   static gint n_reorder_subsubmenus = (sizeof (reorder_subsubmenus) /
  1013.                        sizeof (reorder_subsubmenus[0]));
  1014.  
  1015.   GtkItemFactory *item_factory;
  1016.   GtkWidget *menu_item;
  1017.   GtkWidget *menu;
  1018.   GList *list;
  1019.   gchar *path;
  1020.   gint   i, pos;
  1021.  
  1022.   /*  Move all menu items under "<Toolbox>/Xtns" which are not submenus or
  1023.    *  separators to the top of the menu
  1024.    */
  1025.   pos = 1;
  1026.   menu_item = gtk_item_factory_get_widget (toolbox_factory,
  1027.                        "/Xtns/Module Browser...");
  1028.   if (menu_item && menu_item->parent && GTK_IS_MENU (menu_item->parent))
  1029.     {
  1030.       menu = menu_item->parent;
  1031.  
  1032.       for (list = g_list_nth (GTK_MENU_SHELL (menu)->children, pos); list;
  1033.        list = g_list_next (list))
  1034.     {
  1035.       menu_item = GTK_WIDGET (list->data);
  1036.  
  1037.       if (! GTK_MENU_ITEM (menu_item)->submenu &&
  1038.           GTK_IS_LABEL (GTK_BIN (menu_item)->child))
  1039.         {
  1040.           gtk_menu_reorder_child (GTK_MENU (menu_item->parent),
  1041.                       menu_item, pos);
  1042.           list = g_list_nth (GTK_MENU_SHELL (menu)->children, pos);
  1043.           pos++;
  1044.         }
  1045.     }
  1046.     }
  1047.  
  1048.   /*  Move all menu items under "<Image>/Filters" which are not submenus or
  1049.    *  separators to the top of the menu
  1050.    */
  1051.   pos = 3;
  1052.   menu_item = gtk_item_factory_get_widget (image_factory,
  1053.                        "/Filters/Filter all Layers...");
  1054.   if (menu_item && menu_item->parent && GTK_IS_MENU (menu_item->parent))
  1055.     {
  1056.       menu = menu_item->parent;
  1057.  
  1058.       for (list = g_list_nth (GTK_MENU_SHELL (menu)->children, pos); list;
  1059.        list = g_list_next (list))
  1060.     {
  1061.       menu_item = GTK_WIDGET (list->data);
  1062.  
  1063.       if (! GTK_MENU_ITEM (menu_item)->submenu &&
  1064.           GTK_IS_LABEL (GTK_BIN (menu_item)->child))
  1065.         {
  1066.           gtk_menu_reorder_child (GTK_MENU (menu_item->parent),
  1067.                       menu_item, pos);
  1068.           list = g_list_nth (GTK_MENU_SHELL (menu)->children, pos);
  1069.           pos++;
  1070.         }
  1071.     }
  1072.     }
  1073.  
  1074.   /*  Reorder Rotate plugin menu entries */
  1075.   pos = 2;
  1076.   for (i = 0; i < n_rotate_plugins; i++)
  1077.     {
  1078.       path = g_strconcat ("/Image/Transforms/Rotate/", rotate_plugins[i], NULL);
  1079.       menu_item = gtk_item_factory_get_widget (image_factory, path);
  1080.       g_free (path);
  1081.  
  1082.       if (menu_item && menu_item->parent)
  1083.         {
  1084.           gtk_menu_reorder_child (GTK_MENU (menu_item->parent), menu_item, pos);
  1085.           pos++;
  1086.         }
  1087.     }
  1088.  
  1089.   pos = 2;
  1090.   for (i = 0; i < n_rotate_plugins; i++)
  1091.     {
  1092.       path = g_strconcat ("/Layers/Rotate/", rotate_plugins[i], NULL);
  1093.       menu_item = gtk_item_factory_get_widget (image_factory, path);
  1094.       g_free (path);
  1095.  
  1096.       if (menu_item && menu_item->parent)
  1097.         {
  1098.           gtk_menu_reorder_child (GTK_MENU (menu_item->parent), menu_item, pos);
  1099.           pos++;
  1100.         }
  1101.     }
  1102.  
  1103.   /*  Reorder "<Image>/File"  */
  1104.   for (i = 0; i < n_image_file_entries; i++)
  1105.     {
  1106.       path = g_strconcat ("/File/", image_file_entries[i], NULL);
  1107.       menu_item = gtk_item_factory_get_widget (image_factory, path);
  1108.       g_free (path);
  1109.  
  1110.       if (menu_item && menu_item->parent)
  1111.     gtk_menu_reorder_child (GTK_MENU (menu_item->parent), menu_item, -1);
  1112.     }
  1113.  
  1114.   /*  Reorder menus where plugins registered submenus  */
  1115.   for (i = 0; i < n_reorder_submenus; i++)
  1116.     {
  1117.       item_factory = gtk_item_factory_from_path (reorder_submenus[i]);
  1118.       menu = gtk_item_factory_get_widget (item_factory,
  1119.                       reorder_submenus[i]);
  1120.  
  1121.       if (menu && GTK_IS_MENU (menu))
  1122.     {
  1123.       menus_filters_subdirs_to_top (GTK_MENU (menu));
  1124.     }
  1125.     }
  1126.  
  1127.   for (i = 0; i < n_reorder_subsubmenus; i++)
  1128.     {
  1129.       item_factory = gtk_item_factory_from_path (reorder_subsubmenus[i]);
  1130.       menu = gtk_item_factory_get_widget (item_factory,
  1131.                       reorder_subsubmenus[i]);
  1132.  
  1133.       if (menu && GTK_IS_MENU (menu))
  1134.     {
  1135.       for (list = GTK_MENU_SHELL (menu)->children; list;
  1136.            list = g_list_next (list))
  1137.         {
  1138.           GtkMenuItem *menu_item;
  1139.  
  1140.           menu_item = GTK_MENU_ITEM (list->data);
  1141.  
  1142.           if (menu_item->submenu)
  1143.         menus_filters_subdirs_to_top (GTK_MENU (menu_item->submenu));
  1144.         }
  1145.     }
  1146.     }
  1147.  
  1148.   /*  Move all submenus which registered after "<Image>/Filters/Toys"
  1149.    *  before the separator after "<Image>/Filters/Web"
  1150.    */
  1151.   menu_item = gtk_item_factory_get_widget (image_factory,
  1152.                        "/Filters/---INSERT");
  1153.  
  1154.   if (menu_item && menu_item->parent && GTK_IS_MENU (menu_item->parent))
  1155.     {
  1156.       menu = menu_item->parent;
  1157.       pos = g_list_index (GTK_MENU_SHELL (menu)->children, menu_item);
  1158.  
  1159.       menu_item = gtk_item_factory_get_widget (image_factory,
  1160.                            "/Filters/Toys");
  1161.  
  1162.       if (menu_item && GTK_IS_MENU (menu_item))
  1163.     {
  1164.       GList *list;
  1165.       gint index = 1;
  1166.  
  1167.       for (list = GTK_MENU_SHELL (menu)->children; list;
  1168.            list = g_list_next (list))
  1169.         {
  1170.           if (GTK_MENU_ITEM (list->data)->submenu == menu_item)
  1171.         break;
  1172.  
  1173.           index++;
  1174.         }
  1175.  
  1176.       while ((menu_item = g_list_nth_data (GTK_MENU_SHELL (menu)->children,
  1177.                            index)))
  1178.         {
  1179.           gtk_menu_reorder_child (GTK_MENU (menu), menu_item, pos);
  1180.  
  1181.           pos++;
  1182.           index++;
  1183.         }
  1184.     }
  1185.     }
  1186. }
  1187.  
  1188. static void
  1189. menus_tools_create (ToolInfo *tool_info)
  1190. {
  1191.   GimpItemFactoryEntry entry;
  1192.  
  1193.   if (tool_info->menu_path == NULL)
  1194.     return;
  1195.  
  1196.   entry.entry.path            = tool_info->menu_path;
  1197.   entry.entry.accelerator     = tool_info->menu_accel;
  1198.   entry.entry.callback        = tools_select_cmd_callback;
  1199.   entry.entry.callback_action = tool_info->tool_id;
  1200.   entry.entry.item_type       = NULL;
  1201.   entry.help_page             = tool_info->private_tip;
  1202.   entry.description           = NULL;
  1203.  
  1204.   menus_create_item (image_factory, &entry, (gpointer) tool_info, 2);
  1205. }
  1206.  
  1207. void
  1208. menus_set_sensitive (gchar    *path,
  1209.              gboolean  sensitive)
  1210. {
  1211.   GtkItemFactory *ifactory;
  1212.   GtkWidget *widget = NULL;
  1213.  
  1214.   if (! path)
  1215.     return;
  1216.  
  1217.   if (!menus_initialized)
  1218.     menus_init ();
  1219.  
  1220.   ifactory = gtk_item_factory_from_path (path);
  1221.  
  1222.   if (ifactory)
  1223.     {
  1224.       widget = gtk_item_factory_get_widget (ifactory, path);
  1225.  
  1226.       if (widget)
  1227.     gtk_widget_set_sensitive (widget, sensitive);
  1228.     }
  1229.  
  1230.   if ((!ifactory || !widget) && ! strstr (path, "Script-Fu"))
  1231.     g_warning ("Unable to set sensitivity for menu which doesn't exist:\n%s",
  1232.            path);
  1233. }
  1234.  
  1235. void
  1236. menus_set_state (gchar    *path,
  1237.          gboolean  state)
  1238. {
  1239.   GtkItemFactory *ifactory;
  1240.   GtkWidget *widget = NULL;
  1241.  
  1242.   if (!menus_initialized)
  1243.     menus_init ();
  1244.  
  1245.   ifactory = gtk_item_factory_from_path (path);
  1246.  
  1247.   if (ifactory)
  1248.     {
  1249.       widget = gtk_item_factory_get_widget (ifactory, path);
  1250.  
  1251.       if (widget && GTK_IS_CHECK_MENU_ITEM (widget))
  1252.     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget), state);
  1253.       else
  1254.     widget = NULL;
  1255.     }
  1256.  
  1257.   if ((!ifactory || !widget) && ! strstr (path, "Script-Fu"))
  1258.     g_warning ("Unable to set state for menu which doesn't exist:\n%s\n",
  1259.            path);
  1260. }
  1261.  
  1262. void
  1263. menus_destroy (gchar *path)
  1264. {
  1265.   if (!menus_initialized)
  1266.     menus_init ();
  1267.  
  1268.   gtk_item_factories_path_delete (NULL, path);
  1269. }
  1270.  
  1271. void
  1272. menus_quit (void)
  1273. {
  1274.   gchar *filename;
  1275.  
  1276.   filename = gimp_personal_rc_file ("menurc");
  1277.   gtk_item_factory_dump_rc (filename, NULL, TRUE);
  1278.   g_free (filename);
  1279.  
  1280.   if (menus_initialized)
  1281.     {
  1282.       gtk_object_unref (GTK_OBJECT (toolbox_factory));
  1283.       gtk_object_unref (GTK_OBJECT (image_factory));
  1284.       gtk_object_unref (GTK_OBJECT (load_factory));
  1285.       gtk_object_unref (GTK_OBJECT (save_factory));
  1286.       gtk_object_unref (GTK_OBJECT (layers_factory));
  1287.       gtk_object_unref (GTK_OBJECT (channels_factory));
  1288.       gtk_object_unref (GTK_OBJECT (paths_factory));
  1289.     }
  1290. }
  1291.  
  1292. static void
  1293. menus_last_opened_cmd_callback (GtkWidget *widget,
  1294.                                 gpointer   callback_data,
  1295.                                 guint      num)
  1296. {
  1297.   gchar *filename, *raw_filename;
  1298.   guint num_entries;
  1299.   gint  status;
  1300.  
  1301.   num_entries = g_slist_length (last_opened_raw_filenames); 
  1302.   if (num >= num_entries)
  1303.     return;
  1304.  
  1305.   raw_filename =
  1306.     ((GString *) g_slist_nth_data (last_opened_raw_filenames, num))->str;
  1307.   filename = g_basename (raw_filename);
  1308.  
  1309.   status = file_open (raw_filename, raw_filename);
  1310.  
  1311.   if (status != PDB_SUCCESS &&
  1312.       status != PDB_CANCEL)
  1313.     {
  1314. #ifdef GDK_USE_UTF8_MBS
  1315.       gchar *utf8_raw_filename = g_filename_to_utf8 (raw_filename, -1, NULL, NULL, NULL);
  1316.       g_message (_("Error opening file: %s\n"), utf8_raw_filename);
  1317.       g_free (utf8_raw_filename);
  1318. #else
  1319.       g_message (_("Error opening file: %s\n"), raw_filename);
  1320. #endif
  1321.     }
  1322. }
  1323.  
  1324. static void
  1325. menus_last_opened_update_labels (void)
  1326. {
  1327.   GSList    *filename_slist;
  1328.   GString   *entry_filename;
  1329.   GString   *path;
  1330.   GtkWidget *widget;
  1331.   gint         i;
  1332.   guint      num_entries;
  1333.  
  1334.   entry_filename = g_string_new ("");
  1335.   path = g_string_new ("");
  1336.  
  1337.   filename_slist = last_opened_raw_filenames;
  1338.   num_entries = g_slist_length (last_opened_raw_filenames); 
  1339.  
  1340.   for (i = 1; i <= num_entries; i++)
  1341.     {
  1342. #ifdef GDK_USE_UTF8_MBS
  1343.       {
  1344.     gchar *tmp = g_filename_to_utf8 (g_basename (((GString *) filename_slist->data)->str),
  1345.                      -1, NULL, NULL, NULL);
  1346.     
  1347.     g_string_sprintf (entry_filename, "%d. %s", i,
  1348.               tmp);
  1349.     g_free (tmp);
  1350.       }
  1351. #else
  1352.       g_string_sprintf (entry_filename, "%d. %s", i,
  1353.             g_basename (((GString *) filename_slist->data)->str));
  1354. #endif
  1355.  
  1356.       g_string_sprintf (path, "/File/MRU%02d", i);
  1357.  
  1358.       widget = gtk_item_factory_get_widget (toolbox_factory, path->str);
  1359.       if (widget)
  1360.     {
  1361.       gtk_widget_show (widget);
  1362.  
  1363.       gtk_label_set_text (GTK_LABEL (GTK_BIN (widget)->child),
  1364.                   entry_filename->str);
  1365. #ifdef GDK_USE_UTF8_MBS
  1366.       {
  1367.         gchar *tmp = g_filename_to_utf8 (((GString *) filename_slist->data)->str,
  1368.                          -1, NULL, NULL, NULL);
  1369.         gimp_help_set_help_data (widget, 
  1370.                      tmp, NULL);
  1371.         g_free (tmp);
  1372.       }
  1373. #else
  1374.       gimp_help_set_help_data (widget, 
  1375.                    ((GString *) filename_slist->data)->str, NULL);
  1376. #endif
  1377.     }
  1378.       filename_slist = filename_slist->next;
  1379.     }
  1380.  
  1381.   g_string_free (entry_filename, TRUE);
  1382.   g_string_free (path, TRUE);
  1383. }
  1384.  
  1385. void
  1386. menus_last_opened_add (gchar *filename)
  1387. {
  1388.   GString   *raw_filename;
  1389.   GSList    *list;
  1390.   GtkWidget *menu_item;
  1391.   guint      num_entries;
  1392.  
  1393.   g_return_if_fail (filename != NULL);
  1394.  
  1395.   /*  do nothing if we've already got the filename on the list  */
  1396.   for (list = last_opened_raw_filenames; list; list = g_slist_next (list))
  1397.     {
  1398.       raw_filename = list->data;
  1399.  
  1400.       if (strcmp (raw_filename->str, filename) == 0)
  1401.     {
  1402.       /* the following lines would move the entry to the top
  1403.            *
  1404.        * last_opened_raw_filenames = g_slist_remove_link (last_opened_raw_filenames, list);
  1405.        * last_opened_raw_filenames = g_slist_concat (list, last_opened_raw_filenames);
  1406.        * menus_last_opened_update_labels ();
  1407.        */
  1408.       return;
  1409.     }
  1410.     }
  1411.  
  1412.   num_entries = g_slist_length (last_opened_raw_filenames);
  1413.  
  1414.   if (num_entries == last_opened_size)
  1415.     {
  1416.       list = g_slist_last (last_opened_raw_filenames);
  1417.       if (list)
  1418.     {
  1419.       g_string_free ((GString *)list->data, TRUE);
  1420.       last_opened_raw_filenames = 
  1421.         g_slist_remove (last_opened_raw_filenames, list);
  1422.     }
  1423.     }
  1424.  
  1425.   raw_filename = g_string_new (filename);
  1426.   last_opened_raw_filenames = g_slist_prepend (last_opened_raw_filenames,
  1427.                            raw_filename);
  1428.  
  1429.   if (num_entries == 0)
  1430.     {
  1431.       menu_item = gtk_item_factory_get_widget (toolbox_factory, 
  1432.                            "/File/---MRU");
  1433.       gtk_widget_show (menu_item);
  1434.     }
  1435.  
  1436.   menus_last_opened_update_labels ();
  1437. }
  1438.  
  1439. static void
  1440. menus_init_mru (void)
  1441. {
  1442.   GimpItemFactoryEntry *last_opened_entries;
  1443.   GtkWidget           *menu_item;
  1444.   gchar    *paths;
  1445.   gchar *accelerators;
  1446.   gint     i;
  1447.   
  1448.   last_opened_entries = g_new (GimpItemFactoryEntry, last_opened_size);
  1449.  
  1450.   paths = g_new (gchar, last_opened_size * MRU_MENU_ENTRY_SIZE);
  1451.   accelerators = g_new (gchar, 9 * MRU_MENU_ACCEL_SIZE);
  1452.  
  1453.   for (i = 0; i < last_opened_size; i++)
  1454.     {
  1455.       gchar *path, *accelerator;
  1456.  
  1457.       path = &paths[i * MRU_MENU_ENTRY_SIZE];
  1458.       if (i < 9)
  1459.         accelerator = &accelerators[i * MRU_MENU_ACCEL_SIZE];
  1460.       else
  1461.         accelerator = NULL;
  1462.     
  1463.       last_opened_entries[i].entry.path = path;
  1464.       last_opened_entries[i].entry.accelerator = accelerator;
  1465.       last_opened_entries[i].entry.callback =
  1466.     (GtkItemFactoryCallback) menus_last_opened_cmd_callback;
  1467.       last_opened_entries[i].entry.callback_action = i;
  1468.       last_opened_entries[i].entry.item_type = NULL;
  1469.       last_opened_entries[i].help_page = "file/last_opened.html";
  1470.       last_opened_entries[i].description = NULL;
  1471.  
  1472.       g_snprintf (path, MRU_MENU_ENTRY_SIZE, "/File/MRU%02d", i + 1);
  1473.       if (accelerator != NULL)
  1474.     g_snprintf (accelerator, MRU_MENU_ACCEL_SIZE, "<control>%d", i + 1);
  1475.     }
  1476.  
  1477.   menus_create_items (toolbox_factory, last_opened_size,
  1478.               last_opened_entries, NULL, 2);
  1479.   
  1480.   for (i=0; i < last_opened_size; i++)
  1481.     {
  1482.       menu_item =
  1483.     gtk_item_factory_get_widget (toolbox_factory,
  1484.                      last_opened_entries[i].entry.path);
  1485.       gtk_widget_hide (menu_item);
  1486.     }
  1487.  
  1488.   menu_item = gtk_item_factory_get_widget (toolbox_factory, "/File/---MRU");
  1489.   if (menu_item && menu_item->parent)
  1490.     gtk_menu_reorder_child (GTK_MENU (menu_item->parent), menu_item, -1);
  1491.   gtk_widget_hide (menu_item);
  1492.  
  1493.   menu_item = gtk_item_factory_get_widget (toolbox_factory, "/File/Quit");
  1494.   if (menu_item && menu_item->parent)
  1495.     gtk_menu_reorder_child (GTK_MENU (menu_item->parent), menu_item, -1);
  1496.  
  1497.   g_free (paths);
  1498.   g_free (accelerators);
  1499.   g_free (last_opened_entries);
  1500. }
  1501.  
  1502. /*  This function gets called while browsing a menu created
  1503.  *  by a GtkItemFactory
  1504.  */
  1505. static gint
  1506. menus_item_key_press (GtkWidget   *widget,
  1507.               GdkEventKey *kevent,
  1508.               gpointer     data)
  1509. {
  1510.   GtkItemFactory *item_factory     = NULL;
  1511.   GtkWidget      *active_menu_item = NULL;
  1512.   gchar *factory_path = NULL;
  1513.   gchar *help_path    = NULL;
  1514.   gchar *help_page    = NULL;
  1515.  
  1516.   item_factory = (GtkItemFactory *) data;
  1517.   active_menu_item = GTK_MENU_SHELL (widget)->active_menu_item;
  1518.  
  1519.   /*  first, get the help page from the item
  1520.    */
  1521.   if (active_menu_item)
  1522.     {
  1523.       help_page = (gchar *) gtk_object_get_data (GTK_OBJECT (active_menu_item),
  1524.                          "help_page");
  1525.     }
  1526.  
  1527.   /*  For any key except F1, continue with the standard
  1528.    *  GtkItemFactory callback and assign a new shortcut, but don't
  1529.    *  assign a shortcut to the help menu entries...
  1530.    */
  1531.   if (kevent->keyval != GDK_F1)
  1532.     {
  1533.       if (help_page &&
  1534.       *help_page &&
  1535.       item_factory == toolbox_factory &&
  1536.       (strcmp (help_page, "help/dialogs/help.html") == 0 ||
  1537.        strcmp (help_page, "help/context_help.html") == 0))
  1538.     {
  1539.       gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), 
  1540.                     "key_press_event");
  1541.       return TRUE;
  1542.     }
  1543.       else
  1544.     {
  1545.       return FALSE;
  1546.     }
  1547.     }
  1548.  
  1549.   /*  ...finally, if F1 was pressed over any menu, show it's help page...
  1550.    */
  1551.   gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
  1552.  
  1553.   factory_path = (gchar *) gtk_object_get_data (GTK_OBJECT (item_factory),
  1554.                         "factory_path");
  1555.  
  1556.   if (! help_page ||
  1557.       ! *help_page)
  1558.     help_page = "index.html";
  1559.  
  1560.   if (factory_path && help_page)
  1561.     {
  1562.       gchar *help_string;
  1563.       gchar *at;
  1564.  
  1565.       help_page = g_strdup (help_page);
  1566.  
  1567.       at = strchr (help_page, '@');  /* HACK: locale subdir */
  1568.  
  1569.       if (at)
  1570.     {
  1571.       *at = '\0';
  1572.       help_path   = g_strdup (help_page);
  1573.       help_string = g_strdup (at + 1);
  1574.     }
  1575.       else
  1576.     {
  1577.       help_string = g_strdup_printf ("%s/%s", factory_path, help_page);
  1578.     }
  1579.  
  1580.       gimp_help (help_path, help_string);
  1581.  
  1582.       g_free (help_string);
  1583.       g_free (help_page);
  1584.     }
  1585.   else
  1586.     {
  1587.       gimp_standard_help_func (NULL);
  1588.     }
  1589.  
  1590.   return TRUE;
  1591. }
  1592.  
  1593. /*  set up the callback to catch the "F1" key  */
  1594. static void
  1595. menus_item_realize (GtkWidget *widget,
  1596.             gpointer   data)
  1597. {
  1598.   if (GTK_IS_MENU_SHELL (widget->parent))
  1599.     {
  1600.       if (! gtk_object_get_data (GTK_OBJECT (widget->parent),
  1601.                  "menus_key_press_connected"))
  1602.     {
  1603.       gtk_signal_connect (GTK_OBJECT (widget->parent), "key_press_event",
  1604.                   GTK_SIGNAL_FUNC (menus_item_key_press),
  1605.                   (gpointer) data);
  1606.  
  1607.       gtk_object_set_data (GTK_OBJECT (widget->parent),
  1608.                    "menus_key_press_connected",
  1609.                    (gpointer) TRUE);
  1610.     }
  1611.     }
  1612. }
  1613.  
  1614. static void
  1615. menus_create_item (GtkItemFactory       *item_factory,
  1616.            GimpItemFactoryEntry *entry,
  1617.            gpointer              callback_data,
  1618.            guint                 callback_type)
  1619. {
  1620.   GtkWidget *menu_item;
  1621.  
  1622.   if (!(strstr (entry->entry.path, "tearoff1")))
  1623.     menus_create_branches (item_factory, entry);
  1624.  
  1625.   gtk_item_factory_create_item (item_factory,
  1626.                 (GtkItemFactoryEntry *) entry,
  1627.                 callback_data,
  1628.                 callback_type);
  1629.  
  1630.   menu_item = gtk_item_factory_get_item (item_factory,
  1631.                      ((GtkItemFactoryEntry *) entry)->path);
  1632.  
  1633.   if (menu_item)
  1634.     {
  1635.       gtk_signal_connect_after (GTK_OBJECT (menu_item), "realize",
  1636.                 GTK_SIGNAL_FUNC (menus_item_realize),
  1637.                 (gpointer) item_factory);
  1638.  
  1639.       gtk_object_set_data (GTK_OBJECT (menu_item), "help_page",
  1640.                (gpointer) entry->help_page);
  1641.     }
  1642. }
  1643.  
  1644. static void
  1645. menus_create_items (GtkItemFactory       *item_factory,
  1646.             guint                 n_entries,
  1647.             GimpItemFactoryEntry *entries,
  1648.             gpointer              callback_data,
  1649.             guint                 callback_type)
  1650. {
  1651.   gint i;
  1652.  
  1653.   for (i = 0; i < n_entries; i++)
  1654.     {
  1655.       menus_create_item (item_factory,
  1656.              entries + i,
  1657.              callback_data,
  1658.              callback_type);
  1659.     }
  1660. }
  1661.  
  1662. static void
  1663. menus_init (void)
  1664. {
  1665.   GtkWidget *menu_item;
  1666.   gchar     *filename;
  1667.   gint       i;
  1668.  
  1669.   if (menus_initialized)
  1670.     return;
  1671.  
  1672.   menus_initialized = TRUE;
  1673.  
  1674.   toolbox_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<Toolbox>",
  1675.                       NULL);
  1676.   gtk_object_set_data (GTK_OBJECT (toolbox_factory), "factory_path",
  1677.                (gpointer) "toolbox");
  1678.   gtk_item_factory_set_translate_func (toolbox_factory, menu_translate,
  1679.                        "<Toolbox>", NULL);
  1680.   menus_create_items (toolbox_factory,
  1681.               n_toolbox_entries,
  1682.               toolbox_entries,
  1683.               NULL, 2);
  1684.  
  1685.   menus_init_mru ();
  1686.  
  1687.   image_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<Image>", NULL);
  1688.   gtk_object_set_data (GTK_OBJECT (image_factory), "factory_path",
  1689.                (gpointer) "image");
  1690.   gtk_item_factory_set_translate_func (image_factory, menu_translate,
  1691.                        "<Image>", NULL);
  1692.   menus_create_items (image_factory,
  1693.               n_image_entries,
  1694.               image_entries,
  1695.               NULL, 2);
  1696.  
  1697.   load_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<Load>", NULL);
  1698.   gtk_object_set_data (GTK_OBJECT (load_factory), "factory_path",
  1699.                (gpointer) "open");
  1700.   gtk_item_factory_set_translate_func (load_factory, menu_translate,
  1701.                        "<Load>", NULL);
  1702.   menus_create_items (load_factory,
  1703.               n_load_entries,
  1704.               load_entries,
  1705.               NULL, 2);
  1706.  
  1707.   save_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<Save>", NULL);
  1708.   gtk_object_set_data (GTK_OBJECT (save_factory), "factory_path",
  1709.                (gpointer) "save");
  1710.   gtk_item_factory_set_translate_func (save_factory, menu_translate,
  1711.                        "<Save>", NULL);
  1712.   menus_create_items (save_factory,
  1713.               n_save_entries,
  1714.               save_entries,
  1715.               NULL, 2);
  1716.  
  1717.   layers_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<Layers>", NULL);
  1718.   gtk_object_set_data (GTK_OBJECT (layers_factory), "factory_path",
  1719.                (gpointer) "layers");
  1720.   gtk_item_factory_set_translate_func (layers_factory, menu_translate,
  1721.                        "<Layers>", NULL);
  1722.   menus_create_items (layers_factory,
  1723.               n_layers_entries,
  1724.               layers_entries,
  1725.               NULL, 2);
  1726.  
  1727.   channels_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<Channels>", NULL);
  1728.   gtk_object_set_data (GTK_OBJECT (channels_factory), "factory_path",
  1729.                (gpointer) "channels");
  1730.   gtk_item_factory_set_translate_func (channels_factory, menu_translate,
  1731.                        "<Channels>", NULL);
  1732.   menus_create_items (channels_factory,
  1733.               n_channels_entries,
  1734.               channels_entries,
  1735.               NULL, 2);
  1736.  
  1737.   paths_factory = gtk_item_factory_new (GTK_TYPE_MENU, "<Paths>", NULL);
  1738.   gtk_object_set_data (GTK_OBJECT (paths_factory), "factory_path",
  1739.                (gpointer) "paths");
  1740.   gtk_item_factory_set_translate_func (paths_factory, menu_translate,
  1741.                        "<Paths>", NULL);
  1742.   menus_create_items (paths_factory,
  1743.               n_paths_entries,
  1744.               paths_entries,
  1745.               NULL, 2);
  1746.  
  1747.   for (i = 0; i < num_tools; i++)
  1748.     {
  1749.       menus_tools_create (&tool_info[i]);
  1750.     }
  1751.  
  1752.   /*  reorder <Image>/Image/Colors  */
  1753.   menu_item = gtk_item_factory_get_widget (image_factory,
  1754.                        tool_info[POSTERIZE].menu_path);
  1755.   if (menu_item && menu_item->parent)
  1756.     gtk_menu_reorder_child (GTK_MENU (menu_item->parent), menu_item, 3);
  1757.  
  1758.   {
  1759.     static ToolType color_tools[] = { COLOR_BALANCE,
  1760.                       HUE_SATURATION,
  1761.                       BRIGHTNESS_CONTRAST,
  1762.                       THRESHOLD,
  1763.                       LEVELS,
  1764.                       CURVES };
  1765.     static gint n_color_tools = (sizeof (color_tools) /
  1766.                  sizeof (color_tools[0]));
  1767.     GtkWidget *separator;
  1768.     gint i, pos;
  1769.  
  1770.     pos = 1;
  1771.  
  1772.     for (i = 0; i < n_color_tools; i++)
  1773.       {
  1774.     menu_item =
  1775.       gtk_item_factory_get_widget (image_factory,
  1776.                        tool_info[color_tools[i]].menu_path);
  1777.     if (menu_item && menu_item->parent)
  1778.       {
  1779.         gtk_menu_reorder_child (GTK_MENU (menu_item->parent),
  1780.                     menu_item, pos);
  1781.         pos++;
  1782.       }
  1783.       }
  1784.  
  1785.     if (menu_item && menu_item->parent)
  1786.       {
  1787.     separator = gtk_menu_item_new ();
  1788.     gtk_menu_insert (GTK_MENU (menu_item->parent), separator, pos);
  1789.     gtk_widget_show (separator);
  1790.       }
  1791.   }
  1792.  
  1793.   filename = gimp_personal_rc_file ("menurc");
  1794.   gtk_item_factory_parse_rc (filename);
  1795.   g_free (filename);
  1796. }
  1797.  
  1798. #ifdef ENABLE_NLS
  1799.  
  1800. static gchar *
  1801. menu_translate (const gchar *path,
  1802.             gpointer     data)
  1803. {
  1804.   static gchar *menupath = NULL;
  1805.  
  1806.   GtkItemFactory *item_factory = NULL;
  1807.   gchar *retval;
  1808.   gchar *factory;
  1809.   gchar *translation;
  1810.   gchar *domain = NULL;
  1811.   gchar *complete = NULL;
  1812.   gchar *p, *t;
  1813.  
  1814.   factory = (gchar *) data;
  1815.  
  1816.   if (menupath)
  1817.     g_free (menupath);
  1818.  
  1819.   retval = menupath = g_strdup (path);
  1820.  
  1821.   if ((strstr (path, "/tearoff1") != NULL) ||
  1822.       (strstr (path, "/---") != NULL) ||
  1823.       (strstr (path, "/MRU") != NULL))
  1824.     return retval;
  1825.  
  1826.   if (factory)
  1827.     item_factory = gtk_item_factory_from_path (factory);
  1828.   if (item_factory)
  1829.     {
  1830.       domain = gtk_object_get_data (GTK_OBJECT (item_factory), "textdomain");
  1831.       complete = gtk_object_get_data (GTK_OBJECT (item_factory), "complete");
  1832.     }
  1833.   
  1834.   if (domain)   /*  use the plugin textdomain  */
  1835.     {
  1836.       g_free (menupath);
  1837.       menupath = g_strconcat (factory, path, NULL);
  1838.  
  1839.       if (complete)
  1840.     {
  1841.       /*  
  1842.            *  This is a branch, use the complete path for translation, 
  1843.        *  then strip off entries from the end until it matches. 
  1844.        */
  1845.       complete = g_strconcat (factory, complete, NULL);
  1846.       translation = g_strdup (dgettext (domain, complete));
  1847.  
  1848.       while (complete && *complete && 
  1849.          translation && *translation && 
  1850.          strcmp (complete, menupath))
  1851.         {
  1852.           p = strrchr (complete, '/');
  1853.           t = strrchr (translation, '/');
  1854.           if (p && t)
  1855.         {
  1856.           *p = '\0';
  1857.           *t = '\0';
  1858.         }
  1859.           else
  1860.         break;
  1861.         }
  1862.  
  1863.       g_free (complete);
  1864.     }
  1865.       else
  1866.     {
  1867.       translation = dgettext (domain, menupath);
  1868.     }
  1869.  
  1870.       /* 
  1871.        * Work around a bug in GTK+ prior to 1.2.7 (similar workaround below)
  1872.        */
  1873.       if (strncmp (factory, translation, strlen (factory)) == 0)
  1874.     {
  1875.       retval = translation + strlen (factory);
  1876.       if (complete)
  1877.         {
  1878.           g_free (menupath);
  1879.           menupath = translation;
  1880.         }
  1881.     }
  1882.       else
  1883.     {
  1884.       g_warning ("bad translation for menupath: %s", menupath);
  1885.       retval = menupath + strlen (factory);
  1886.       if (complete)
  1887.         g_free (translation);
  1888.     }
  1889.     }
  1890.   else   /*  use the gimp textdomain  */
  1891.     {
  1892.       if (complete)
  1893.     {
  1894.       /*  
  1895.            *  This is a branch, use the complete path for translation, 
  1896.        *  then strip off entries from the end until it matches. 
  1897.        */
  1898.       complete = g_strdup (complete);
  1899.       translation = g_strdup (gettext (complete));
  1900.       
  1901.       while (*complete && *translation && strcmp (complete, menupath))
  1902.         {
  1903.           p = strrchr (complete, '/');
  1904.           t = strrchr (translation, '/');
  1905.           if (p && t)
  1906.         {
  1907.           *p = '\0';
  1908.           *t = '\0';
  1909.         }
  1910.           else
  1911.         break;
  1912.         }
  1913.       g_free (complete);
  1914.     }
  1915.       else
  1916.     translation = gettext (menupath);
  1917.  
  1918.       if (*translation == '/')
  1919.     {
  1920.       retval = translation;
  1921.       if (complete)
  1922.         {
  1923.           g_free (menupath);
  1924.           menupath = translation;
  1925.         }
  1926.     }
  1927.       else
  1928.     {
  1929.       g_warning ("bad translation for menupath: %s", menupath);
  1930.       if (complete)
  1931.         g_free (translation);
  1932.     }
  1933.     }
  1934.   
  1935.   return retval;
  1936. }
  1937.  
  1938. #endif  /*  ENABLE_NLS  */
  1939.  
  1940. static gint
  1941. tearoff_delete_cb (GtkWidget *widget, 
  1942.            GdkEvent  *event,
  1943.            gpointer   data)
  1944. {
  1945.   /* Unregister if dialog is deleted as well */
  1946.   dialog_unregister (widget);
  1947.  
  1948.   return TRUE; 
  1949. }
  1950.  
  1951. static void   
  1952. tearoff_cmd_callback (GtkWidget *widget,
  1953.               gpointer   callback_data,
  1954.               guint      callback_action)
  1955. {
  1956.   if (GTK_IS_TEAROFF_MENU_ITEM (widget))
  1957.     {
  1958.       GtkTearoffMenuItem *tomi = (GtkTearoffMenuItem *) widget;
  1959.  
  1960.       if (tomi->torn_off)
  1961.     {
  1962.       GtkWidget *top = gtk_widget_get_toplevel (widget);
  1963.  
  1964.       /* This should be a window */
  1965.       if (!GTK_IS_WINDOW (top))
  1966.         {
  1967.           g_message ("tearoff menu not in top level window");
  1968.         }
  1969.       else
  1970.         {
  1971.           dialog_register (top);
  1972.           gtk_signal_connect (GTK_OBJECT (top), "delete_event",
  1973.                   GTK_SIGNAL_FUNC (tearoff_delete_cb),
  1974.                   NULL);
  1975.  
  1976.           gtk_object_set_data (GTK_OBJECT (widget), "tearoff_menu_top",
  1977.                    top);
  1978.  
  1979.           gimp_dialog_set_icon (GTK_WINDOW (top));
  1980.         }
  1981.     }
  1982.       else
  1983.     {
  1984.       GtkWidget *top;
  1985.  
  1986.       top = (GtkWidget *) gtk_object_get_data (GTK_OBJECT (widget),
  1987.                            "tearoff_menu_top");
  1988.  
  1989.       if (!top)
  1990.         g_message ("can't unregister tearoff menu top level window");
  1991.       else
  1992.         dialog_unregister (top);
  1993.     }
  1994.     }
  1995. }
  1996.  
  1997. #ifdef ENABLE_DEBUG_ENTRY
  1998.  
  1999. #include <unistd.h>
  2000.  
  2001. static void
  2002. menus_debug_recurse_menu (GtkWidget *menu,
  2003.               gint       depth,
  2004.               gchar     *path)
  2005. {
  2006.   GtkItemFactory      *item_factory;
  2007.   GtkItemFactoryItem  *item;
  2008.   GtkItemFactoryClass *class;
  2009.   GtkWidget           *menu_item;
  2010.   GList   *list;
  2011.   gchar   *label;
  2012.   gchar   *help_page;
  2013.   gchar   *help_path;
  2014.   gchar   *factory_path;
  2015.   gchar   *hash;
  2016.   gchar   *full_path;
  2017.   gchar   *accel;
  2018.   gchar   *format_str;
  2019.  
  2020.   for (list = GTK_MENU_SHELL (menu)->children; list; list = g_list_next (list))
  2021.     {
  2022.       menu_item = GTK_WIDGET (list->data);
  2023.       
  2024.       if (GTK_IS_LABEL (GTK_BIN (menu_item)->child))
  2025.     {
  2026.       gtk_label_get (GTK_LABEL (GTK_BIN (menu_item)->child), &label);
  2027.       full_path = g_strconcat (path, "/", label, NULL);
  2028.       class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
  2029.       item = g_hash_table_lookup (class->item_ht, full_path);
  2030.       if (item)
  2031.         {
  2032.           accel = gtk_accelerator_name (item->accelerator_key, 
  2033.                         item->accelerator_mods);
  2034.         }
  2035.       else
  2036.         {
  2037.           accel = NULL;
  2038.         }
  2039.  
  2040.       item_factory = gtk_item_factory_from_path (path);
  2041.       if (item_factory)
  2042.         {
  2043.           factory_path = (gchar *) gtk_object_get_data (GTK_OBJECT (item_factory),
  2044.                                 "factory_path");
  2045.           help_page = g_strconcat (factory_path ? factory_path : "",
  2046.                        factory_path ? G_DIR_SEPARATOR_S : "",
  2047.                        (gchar *) gtk_object_get_data (GTK_OBJECT (menu_item), 
  2048.                                       "help_page"),
  2049.                        NULL);
  2050.         }
  2051.       else
  2052.         {
  2053.           help_page = g_strdup ((gchar *) gtk_object_get_data (GTK_OBJECT (menu_item), 
  2054.                                    "help_page"));
  2055.         } 
  2056.  
  2057.       if (help_page)
  2058.         {
  2059.           help_path = g_strconcat (gimp_data_directory (), G_DIR_SEPARATOR_S, 
  2060.                        "help", G_DIR_SEPARATOR_S, 
  2061.                        "C", G_DIR_SEPARATOR_S,
  2062.                        help_page, NULL);
  2063.  
  2064.           if ((hash = strchr (help_path, '#')) != NULL)
  2065.         *hash = '\0';
  2066.  
  2067.           if (access (help_path, R_OK))
  2068.         {
  2069.           g_free (help_path);
  2070.           help_path = g_strconcat ("! ", help_page, NULL);
  2071.           g_free (help_page);
  2072.           help_page = help_path;
  2073.         }
  2074.           else
  2075.         {
  2076.           g_free (help_path);
  2077.         }
  2078.         }
  2079.  
  2080.       format_str = g_strdup_printf ("%%%ds%%%ds %%-20s %%s\n", 
  2081.                     depth * 2, depth * 2 - 40);
  2082.       g_print (format_str, 
  2083.            "", label, accel ? accel : "", help_page ? help_page : "");
  2084.       g_free (format_str);
  2085.       g_free (help_page);
  2086.  
  2087.       if (GTK_MENU_ITEM (menu_item)->submenu)
  2088.         menus_debug_recurse_menu (GTK_MENU_ITEM (menu_item)->submenu, 
  2089.                       depth + 1, full_path);
  2090.  
  2091.       g_free (full_path);
  2092.     }                  
  2093.     }
  2094. }
  2095.  
  2096. static void
  2097. menus_debug_cmd_callback (GtkWidget *widget,
  2098.               gpointer   callback_data,
  2099.               guint      callback_action)
  2100. {
  2101.   gint  n_factories = 7;
  2102.   GtkItemFactory       *factories[7];
  2103.   GimpItemFactoryEntry *entries[7];
  2104.  
  2105.   GtkWidget *menu_item;
  2106.   gint       i;
  2107.  
  2108.   factories[0] = toolbox_factory;
  2109.   factories[1] = image_factory;
  2110.   factories[2] = layers_factory;
  2111.   factories[3] = channels_factory;
  2112.   factories[4] = paths_factory;
  2113.   factories[5] = load_factory;
  2114.   factories[6] = save_factory;
  2115.  
  2116.   entries[0] = toolbox_entries;
  2117.   entries[1] = image_entries;
  2118.   entries[2] = layers_entries;
  2119.   entries[3] = channels_entries;
  2120.   entries[4] = paths_entries;
  2121.   entries[5] = load_entries;
  2122.   entries[6] = save_entries;
  2123.   
  2124.   /*  toolbox needs special treatment  */
  2125.   g_print ("%s\n", factories[0]->path);
  2126.  
  2127.   menu_item = gtk_item_factory_get_item (factories[0], "/File");
  2128.   if (menu_item && menu_item->parent && GTK_IS_MENU_BAR (menu_item->parent))
  2129.     menus_debug_recurse_menu (menu_item->parent, 1, factories[0]->path);
  2130.  
  2131.   g_print ("\n");
  2132.  
  2133.   for (i = 1; i < n_factories; i++)
  2134.     {
  2135.       g_print ("%s\n", factories[i]->path);
  2136.  
  2137.       menu_item = gtk_item_factory_get_item (factories[i], entries[i][0].entry.path);
  2138.       if (menu_item && menu_item->parent && GTK_IS_MENU (menu_item->parent))
  2139.     menus_debug_recurse_menu (menu_item->parent, 1, factories[i]->path);
  2140.  
  2141.       g_print ("\n");
  2142.     }
  2143. }
  2144. #endif  /*  ENABLE_DEBUG_ENTRY  */
  2145.